<?php

/**
 * Permission Installer component
 *
 * Manages user logins and permissions.
 *
 * PHP 5
 *
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
 * @link          http://cakephp.org CakePHP(tm) Project
 * @package       Cake.Controller.Component
 * @since         CakePHP(tm) v 0.10.0.1076
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 */
App::uses('Component', 'Controller');

/**
 * Authentication control component class
 *
 * Binds access control with user authentication and session management.
 *
 * @package       Cake.Controller.Component
 * @link http://book.cakephp.org/view/1250/Authentication
 */
class InstallerComponent extends Component {

    public $actionPath = 'controllers';

    /**
     * Permission generate
     * 
     * Plugin & controller in parent folder app/Controller/ does not duplicate name
     *
     * @return array log
     */
    function permission($plugin = null) {
        $log = array();
        $Aco = $this->_Collection->load('Acl')->Aco;

        $baseMethods = get_class_methods('AppController');
        $pluginDot = $pluginMessage = '';

        $actionPath = $this->actionPath;
        $root = $Aco->node($actionPath);
        if (!$root) {
            $Aco->create(array('parent_id' => null, 'model' => null, 'alias' => $actionPath));
            $root = $Aco->save();
            $root['Aco']['id'] = $Aco->id;
            $log[] = __d('debug', 'Created permission for all node', $plugin);
        } else {
            $root = $root[0];
        }

        if ($plugin) {
            App::uses($plugin . 'AppController', $plugin . '.Controller');
            if (class_exists($plugin . 'AppController')) {
                $baseMethods = get_class_methods($plugin . 'AppController');
            }
            $pluginDot = $plugin . '.';
            $actionPath .='/' . $plugin;
            $pluginMessage = ' ' . __d('system', 'of plugin %s', $plugin);
            $_rootKey = $root['Aco']['id'];
            $root = $Aco->node($actionPath);
            if (!$root) {
                $Aco->create(array('parent_id' => $_rootKey, 'model' => null, 'alias' => $plugin));
                $root = $Aco->save();
                $root['Aco']['id'] = $Aco->id;
                $log[] = __d('debug', 'Created permission node for plugin %s', $plugin);
            } else {
                $root = $root[0];
            }
        }

        $Controllers = App::objects($pluginDot . 'controller', null, false);

        foreach ($Controllers as $Controller) {
            App::uses($Controller, $pluginDot . 'Controller');
            $controllerName = preg_replace('/Controller$/', '', $Controller);
            if ($controllerName == $plugin . 'App' || $controllerName == 'CakeError') {
                continue;
            }
            if (!class_exists($Controller)) {
                $log[] = __d('debug', 'Controller %s%s does exist', array($controllerName, $pluginMessage));
                continue;
            }
            $controllerNode = $Aco->node($actionPath . '/' . $controllerName);
            if (!$controllerNode) {
                $Aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $controllerName));
                $controllerNode = $Aco->save();
                $controllerNode['Aco']['id'] = $Aco->id;
                $log[] = __d('debug', 'Created permission node for %s%s', array($controllerName, $pluginMessage));
            } else {
                $controllerNode = $controllerNode[0];
            }
            $methods = get_class_methods($Controller);
            foreach ($methods AS $k => $method) {
                if (strpos($method, '_', 0) === 0 || in_array($method, $baseMethods)) {
                    unset($methods[$k]);
                    continue;
                }
                $methodNode = $Aco->node($actionPath . '/' . $controllerName . '/' . $method);
                if (!$methodNode) {
                    $Aco->create(array('parent_id' => $controllerNode['Aco']['id'], 'model' => null, 'alias' => $method));
                    $methodNode = $Aco->save();
                    $log[] = __d('debug', 'Created permission node for %s->%s%s', array($controllerName, $method, $pluginMessage));
                }
            }
        }
        return $log;
    }

    /**
     * Permission settings
     * 
     * Plugin & controller in parent folder app/Controller/ does not duplicate name
     *
     *  {{{
     *   $intaller->permissionAdd('Products/home', 'Role', 1);
     *   $intaller->permissionAdd(10, 'Role', 1);
     *  }}}
     * @var boolean
     */
    function permissionChange($aco, $model, $key, $value) {
        $Acl = $this->_Collection->load('Acl');
        $Acl->Aro->cacheQueries = false;
        $aro = $Acl->Aro->find('first', array(
            'conditions' => array(
                'Aro.model' => $model,
                'Aro.foreign_key' => $key,
            ),
            'fields' => array(
                'Aro.id'
            ),
            'recursive' => -1)
        );
        if (empty($aro)) {
            $Acl->Aro->create();
            $Acl->Aro->save(array(
                'model' => $model,
                'foreign_key' => $key,
            ));
            $aro = $Acl->Aro->id;
        } else {
            $aro = $aro['Aro']['id'];
        }
        if (!is_numeric($aco)) {
            $aco = $Acl->Aco->node($this->actionPath . '/' . $aco);
            if (empty($aco)) {
                return false;
            }
            $aco = $aco[0]['Aco']['id'];
        } else {
            if (!$Acl->Aco->find('count', array('recursive' => -1, 'conditions' => array('id' => $aco)))) {
                return false;
            }
        }

        if (empty($value) && intval($value) != -1) {
            if (!$Acl->Aco->Permission->find('count', array(
                        'conditions' => array(
                            'Permission.aro_id' => $aro,
                            'Permission.aco_id' => $aco,
                        ),
                        'recursive' => -1))) {
                return true;
            }
        }

        $value = array(
            '_read' => $value,
            '_create' => $value,
            '_update' => $value,
            '_delete' => $value
        );
        $permission = $Acl->Aco->Permission->find('first', array(
            'conditions' => array(
                'Permission.aro_id' => $aro,
                'Permission.aco_id' => $aco,
            ),
            'recursive' => -1));

        $Acl->Aco->Permission->create();
        if ($permission) {
            $Acl->Aco->Permission->id = $permission['Permission']['id'];
            if (Set::contains($permission['Permission'], $value)) {
                return true;
            }
        }
        $value = array_merge($value, array('aro_id' => $aro, 'aco_id' => $aco));
        return $Acl->Aco->Permission->save($value);
    }

}

?>
